OpenBuildings GenerativeComponents Help

Record and Table Types

The Record Type

A record is an ad-hoc data structure having named properties and values.

One way to define a record is “in line”. The general form is:

	{name=expression, name=expression, ... }

Each expression may resolve to a value of any type. (Only those resultant values are stored in the record.)

Here’s an example:

	record rec = {x=0.7, y=Sqrt(100), color=Colors.Blue};

Alternatively, we can define an empty record structure, to be filled in later:

	record rec = {x=, y=, color=};

Alternatively, we can construct a record programmatically:

	record rec;
	rec.Add('x', 0.7);
	rec.Add('y', Sqrt(100));
	string name = 'color';
	color value = Colors.Blue;
	rec.Add(name, value); 

Regardless of how it’s been created, we can use a record instance just like any other object that has properties:

	Print(rec.y);            // Prints "10".
	rec.color = Colors.Red;

The Table Type

A table is an associative collection of keys and values. In some other programming languages, this kind of collection is called a dictionary.

One way to define a table is “in line”. The general form is:

	{[keyExpression]=valueExpression, [keyExpression]=valueExpression, … }

Note that each keyExpression is enclosed in square brackets. That's what distinguishes table-creation notation from record-creation notation.

Each keyExpression and valueExpression may resolve to a value of any type. (Only those resultant values are stored in the table.)

Here’s an example:

	table tab = {[5]='five', [line01]=line01.Length, ['how now']='brown cow', [Sqrt(16)]=Series(1,10,1)}

Alternatively, we can construct a table programmatically:

	table tab = {};
	tab.Add(5, 'five');
	tab.Add(line01, line01.Length);
	tab.Add('how now', 'brown cow');
	double key = Sqrt(16);
	int[] value = Series(1,10,1);
	tab.Add(key, value);

Regardless of how it’s been created, you can use a table instance in the same way we would use a list, except that the index key can be any object rather than (necessarily) an integer:

	Print(tab['how now']);    // Prints "brown cow".
	Print(tab[4]};            // Prints "{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}".
	tab[line01] = point02.X;

One purpose of a table is to preserve a set of values so that they can be compared later. For example:

	// Create and populate the table.
	
	global table lineLengths = {};           // Create an empty table.
	var lines = Nodes(n => n is Line);       // Get all of the Line nodes in the GC model.
	foreach (line in lines)                  // Add the length of each line to the table,
	    lineLengths.Add(line, line.Length);  // keyed by the line, itself.
	
	// Do something that causes one or more lines to change.
	
	// Then, afterwards...
	
	foreach (line in table.Keys()) // Step through all of the keys in the table, which are 
	{                              // (still) all of the Line nodes we're interested in.
	    var diff = line.Length – lineLengths[line];  // If the line's length has changed,  show
	    if (diff != 0)                               // the difference in the script console..
	         PrintFormat("The length of {0} has changed by {1}.", line, diff);
	}

Another purpose of a table is to serve as a lookup/conversion table. For example:

	global table casementSizes = {   // Each key is a casement model number. Each value is a record
	                                 // providing the height and width dimensions of that model.
	
	                                 [1824]={height=2.0, width=1.5},
	                                 [1828]={height=2.4, width=1.5},
	                                 [1836]={height=3.0, width=1.5},
	
	                                 ... (etc.) ...
	                             };;
	
	// Subsequently, we might enter the following expression into the YTranslation property of
	// one of our Point nodes. (Imagine we also have an Expression node named "casementNumber".)
	
	casementSizes[casementNumber].Height

Interoperability Between Records and Tables

Records and tables are type-compatible. When a record is converted to a table, all of the record’s property names become string keys within the new table. When a table is converted to a record, only those table keys that are legal property names become properties within the new record; other items in the table are ignored.

Under the hood, a record is implemented as a special kind of table. Consequently, all records support the same methods as tables. For example, we can say:

	record rec = { ... (something) ... };
	double value = rec.GetItem('z', 0.0};  // GetItem is a table method. If the record "rec" includes
	                                       // a property named "z", that property's value is returned.
	                                       // Otherwise, the given default value, 0.0, is returned.